package cn.bfay.lion.rest.client;

import cn.bfay.lion.rest.client.req.AddProductReq;
import cn.bfay.lion.rest.client.rsp.GeneralPromotionLinkRsp;
import cn.bfay.lion.rest.client.rsp.ProductDetailInfoRsp;
import cn.bfay.lion.rest.client.rsp.ProductInfoRsp;
import cn.bfay.lion.rest.error.RestBusinessError;
import cn.bfay.web.exception.BizException;
import cn.bfay.web.result.BaseResult;
import cn.bfay.web.result.PageResult;
import feign.FeignException;
import feign.Response;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * JingdongClient.
 *
 * @author wangjiannan
 */
@Lazy
@FeignClient(name = "${jingdong.service-id}", configuration = JingdongClient.ClientConfiguration.class)
public interface JingdongClient {
    @PostMapping(value = "/jingdong/product/add-product-by-skuid")
    BaseResult addProductBySkuid(@RequestBody AddProductReq addProductReq);

    @GetMapping(value = "/jingdong/product/get-product-info-by-skuid")
    ProductInfoRsp getProductInfoBySkuid(@RequestParam("skuid") String skuid);

    @GetMapping(value = "/jingdong/product/get-product-info-by-skuids")
    List<ProductInfoRsp> getProductInfoBySkuids(@RequestParam("skuids") String skuids);

    @GetMapping(value = "/jingdong/product/get-product-info-by-paging")
    PageResult<ProductInfoRsp> getProductInfoByPaging(@RequestParam(value = "name", required = false) String name,
                                                      @RequestParam("pageNum") Long pageNum,
                                                      @RequestParam("pageSize") Long pageSize);

    @GetMapping(value = "/jingdong/product/get-product-detail-infos")
    List<ProductDetailInfoRsp> getProductDetailInfos(@RequestParam("skuid") String skuid);

    @GetMapping(value = "/jingdong/product/get-promotion-common")
    GeneralPromotionLinkRsp getPromotionCommon(@RequestParam("skuid") String skuid);

    /**
     * client自定义配置.
     */
    class ClientConfiguration {
        //不能使用@Resource
        @Autowired
        private ObjectFactory<HttpMessageConverters> messageConverters;

        @Bean
        public feign.codec.Decoder jingdongDecoder() {
            return new ResponseEntityDecoder(new JingdongClient.ClientConfiguration.JingdongDecoder(messageConverters));
        }

        private static class JingdongDecoder extends CommonDecoder {
            public JingdongDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
                super(messageConverters);
            }

            @Override
            public Object decode(Response response, Type type) throws IOException, FeignException {

                BaseResult baseResult = (BaseResult) super.decode(response, BaseResult.class);

                if (baseResult == null) {
                    throw new BizException(RestBusinessError.SYSTEM_ERROR);
                }

                if (!StringUtils.equalsIgnoreCase(baseResult.getCode(), "0")) {
                    throw new BizException(baseResult.getCode(), baseResult.getMessage());
                }

                // ((ParameterizedTypeImpl) type).rawType.equals(List.class)
                if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(List.class)) {
                    LinkedHashMap<String, Object> items = (LinkedHashMap<String, Object>) baseResult.getData();
                    return convertGenericList((ParameterizedType) type, items);
                } else if (type.equals((Type) BaseResult.class)) {
                    return baseResult;
                } else {
                    return mapper.convertValue(baseResult.getData(), mapper.constructType(type));
                }
            }
        }
    }

}
